/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package server;

import java.io.StringWriter;
import java.sql.*;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
import javax.ws.rs.core.Response.*;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;
import org.w3c.dom.*;

/**
 * REST Web Service
 *
 * @author kempe
 */
@Path("article")
public class ArticleService {

    @Context
    private UriInfo context;
    
    //Database variables
    Connection conn = null;
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    
    //XML variables
    DocumentBuilderFactory fac;
    DocumentBuilder build;

    /**
     * Creates a new instance of ArticleService
     * Create a database connection and display a message if somthing fails
     */ 
    public ArticleService() {
        try {
            //setup database
            String usr= "***";
            String pwd = "***";
            Class.forName("com.mysql.jdbc.Driver");
            String url = "jdbc:mysql://***:3306/datateknik_soa";
            conn = DriverManager.getConnection(url, usr, pwd);
            
            //setup xml variables
            fac = DocumentBuilderFactory.newInstance();
            build = fac.newDocumentBuilder();
        }
        catch(Exception ex) {
            ResponseBuilder builder = Response.status(Status.SERVICE_UNAVAILABLE);
            builder.type("text/html");
            builder.entity("<h3>Init failure, please conntact site-administrator</h3>");
            throw new WebApplicationException(builder.build());
        }
    }

    
    /**
     * Get a list of articles availible. 
     * Lets the consumer decide the number of results to get back,
     * defults to 10 results
     * 
     * @param size  number of results
     * @return String/XML  list of articles
     */
    @GET
    @Produces("application/xml")
    @Path("/list")
    public String getArticles(@QueryParam("limit") @DefaultValue("10") int limit) {
        String xml;
        Document doc = build.newDocument();
        Element root = doc.createElement("articleList");
        
        try {
            pstmt = conn.prepareStatement("CALL get_articles(?)");
            pstmt.setInt(1, limit);
            rs = pstmt.executeQuery();
            
            while(rs.next()) {
                Element article = doc.createElement("article");
                Element id = doc.createElement("id");
                Element title = doc.createElement("title");
                
                id.appendChild(doc.createTextNode(""+rs.getInt("article_id")));
                title.appendChild(doc.createTextNode(""+rs.getString("article_title")));

                article.appendChild(id);
                article.appendChild(title);
                root.appendChild(article);
            }
            doc.appendChild(root);
            xml = xmlToString(doc);
            
        }
        catch(Exception ex) {
            xml = "<error>"+ex.getMessage()+"</error>";
        }
        return xml;
    }
    
    
    /**
     * Get a list of articles availible. based on a keyword
     * Lets the consumer decide the number of results to get back,
     * defults to 10 results
     * 
     * @param size  number of results
     * @return String/XML  list of articles
     */
    @GET
    @Produces("application/xml")
    @Path("/list/{keyword}")
    public String getArticles(@QueryParam("limit") @DefaultValue("250") int limit, @PathParam("keyword") String keyword) {
        String xml;
        Document doc = build.newDocument();
        Element root = doc.createElement("articleList");
        
        try {
            pstmt = conn.prepareStatement("CALL get_article_by_keyword(?, ?)");
            pstmt.setInt(1, limit);
            pstmt.setString(2, keyword);
            rs = pstmt.executeQuery();
            
            while(rs.next()) {
                Element article = doc.createElement("article");
                Element id = doc.createElement("id");
                Element title = doc.createElement("title");
                
                id.appendChild(doc.createTextNode(""+rs.getInt("article_id")));
                title.appendChild(doc.createTextNode(rs.getString("article_title")));

                article.appendChild(id);
                article.appendChild(title);
                root.appendChild(article);
            }
            doc.appendChild(root);
            xml = xmlToString(doc);
            
        }
        catch(Exception ex) {
            xml = "<error>"+ex.getMessage()+"</error>";
        }
        return xml;
    }
    
    
    /**
     * Get all data of one article
     * 
     * @param articleID  id of the article to get
     * @return String/XML  Article data
     */
    @GET
    @Produces("application/xml")
    @Path("/{id: \\d+}")    // "/{id:} = all strings that dont have / in them after the root path goes here
                            // "\\d+" regulare expression, limits the string to be numbers
    public String getArticle(@PathParam("id") int articleID) {
        String xml;
        Document doc = build.newDocument();
        Element root = doc.createElement("article");
        
        try {
            pstmt = conn.prepareStatement("CALL get_article(?)");
            pstmt.setInt(1, articleID);
            rs = pstmt.executeQuery();
            
            if(rs.next()) {
                Element id = doc.createElement("id");
                Element title = doc.createElement("title");
                Element content = doc.createElement("content");
                Element date = doc.createElement("date");
                Element author = doc.createElement("authorID");
                
                id.appendChild(doc.createTextNode(""+rs.getInt("article_id")));
                title.appendChild(doc.createTextNode(rs.getString("article_title")));
                content.appendChild(doc.createTextNode(rs.getString("article_content")));
                date.appendChild(doc.createTextNode(rs.getString("article_date")));
                author.appendChild(doc.createTextNode(rs.getString("author_id")));

                root.appendChild(id);
                root.appendChild(title);
                root.appendChild(content);
                root.appendChild(date);
                root.appendChild(author);
            }
            doc.appendChild(root);
            xml = xmlToString(doc);
            
        }
        catch(Exception ex) {
            xml = "<error>"+ex.getMessage()+"</error>";
        }
        return xml;
    }
    
    /**
     * Get the author from article id
     * 
     * @param articleID
     * @return String/XML  author data
     */
    @GET
    @Produces("application/xml")
    @Path("/author/{id: \\d+}")
    public String getAuthor(@PathParam("id") int authorID) {
        String xml;
        Document doc = build.newDocument();
        Element root = doc.createElement("name");
        
        
        
        try {
            pstmt = conn.prepareStatement("SELECT author_name FROM author WHERE author_id=(?)");
            pstmt.setInt(1, authorID);
            rs = pstmt.executeQuery();
            
            if(rs.next()) {
                //Element id = doc.createElement("id");
                //Element name = doc.createElement("name");
                
                //id.appendChild(doc.createTextNode(""+rs.getInt("author_id")));
                root.appendChild(doc.createTextNode(rs.getString("author_name")));

                //root.appendChild(id);
                //root.appendChild(name);
            }
            doc.appendChild(root);
            xml = xmlToString(doc);
            
        }
        catch(Exception ex) {
            xml = "<error>"+ex.getMessage()+"</error>";
        }
        return xml;
    }
    
    /**
     * Get the keywords of an article
     * 
     * @param articleID
     * @return String/XML  keyword data
     */
    @GET
    @Produces("application/xml")
    @Path("/{id: \\d+}/keywords")
    public String getArticleKeywords(@PathParam("id") int articleID) {
        String xml;
        Document doc = build.newDocument();
        Element root = doc.createElement("keywordList");
        
        try {
            pstmt = conn.prepareStatement("CALL get_article_keywords(?)");
            pstmt.setInt(1, articleID);
            rs = pstmt.executeQuery();
            
            while(rs.next()) {
                Element keyword = doc.createElement("keyword");
                //Element id = doc.createElement("id");
                Element keyword_title = doc.createElement("word");
                
                //id.appendChild(doc.createTextNode(""+rs.getInt("keyword_id")));
                keyword_title.appendChild(doc.createTextNode(rs.getString("keyword_keyword")));

                //keyword.appendChild(id);
                keyword.appendChild(keyword_title);
                root.appendChild(keyword);
            }
            doc.appendChild(root);
            xml = xmlToString(doc);
            
        }
        catch(Exception ex) {
            xml = "<error>"+ex.getMessage()+"</error>";
        }
        return xml;
    }
    
    /**
     * Get a list of all the keywords in the database
     * @return String/XML a list of all keywords availible
     */
    @GET
    @Produces("application/xml")
    @Path("/keywords")
    public String getKeywords() {
        String xml;
        Document doc = build.newDocument();
        Element root = doc.createElement("keywordList");
        
        try {
            pstmt = conn.prepareStatement("CALL get_keywords()");
            rs = pstmt.executeQuery();
            
            while(rs.next()) {
                Element keyword = doc.createElement("keyword");
                Element id = doc.createElement("id");
                Element keyword_title = doc.createElement("word");
                
                id.appendChild(doc.createTextNode(""+rs.getInt("keyword_id")));
                keyword_title.appendChild(doc.createTextNode(rs.getString("keyword_keyword")));

                keyword.appendChild(id);
                keyword.appendChild(keyword_title);
                root.appendChild(keyword);
            }
            doc.appendChild(root);
            xml = xmlToString(doc);
            
        }
        catch(Exception ex) {
            xml = "<error>"+ex.getMessage()+"</error>";
        }
        return xml;
    }
    
    /**
     * Add a new article to the database.
     * Example input: 
     * <article>
     *   <title>title</title>
     *   <content>content</content>
     *   <keywords>
     *     <keyword>1</keyword>
     *     <keyword>2</keyword>
     *     ...
     *   </keywords>
     *   <author>name<author>
     * </article>
     * 
     * @return String/XML  success or error
     */
    @PUT
    @Produces("application/xml")
    @Consumes("application/xml")
    public String addArticle(String message) {
        System.out.print("add article: "+message);
        return "<return>skapa ny artikel</return>";
    }
    
    
    /**
     * Transform xml to string to send
     * @param doc
     * @return 
     */
    private String xmlToString(Document doc) {
        try {
            StringWriter buffer = new StringWriter();
            TransformerFactory transFactory = TransformerFactory.newInstance();
            Transformer transformer = transFactory.newTransformer();
            transformer.transform(new DOMSource(doc), new StreamResult(buffer));
            return buffer.toString();
        } catch (Throwable t) {
            return "ERROR: " + t.getMessage();
        }
    }
}
